package simulation;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
import physicalObjects.Bar;
import physicalObjects.Mass;
import physicalObjects.Muscle;
import physicalObjects.Spring;

/**
 *
 * @author Professor Duvall
 * modified by Michael Elgart and Bruce Fu
 *
 */
public class Factory {

    /**
     * Reads the input file. Build assemblies and set up force parameters.
     * @param sim Simulation where the data will be loaded
     * @param modelFile File where the data will be read from
     */
    public void loadModel (Simulation sim, File modelFile) {
        try {
            Scanner input = new Scanner(modelFile);
            while (input.hasNext()) {
                Scanner line = new Scanner(input.nextLine());
                if (line.hasNext()) {
                    String type = line.next();
                    if ("mass".equals(type)) {
                        sim.add(massCommand(line));
                    }
                    else if ("spring".equals(type)) {
                        sim.add(springCommand(line, sim));
                    }
                    else if ("muscle".equals(type)) {
                        sim.add(muscleCommand(line, sim));
                    }
                    else if ("gravity".equals(type)) {
                        setGravity(line);
                    }
                    else if ("viscosity".equals(type)) {
                        setViscosity(line);
                    }
                    else if ("centermass".equals(type)) {
                        setCenterMassForce(line);
                    }
                    else if ("wall".equals(type)) {
                        setWallForce(line);
                    }
                }
            }
            input.close();
        }
        catch (FileNotFoundException e) {
            // should not happen because File came from user selection
            e.printStackTrace();
        }
    }

    /**
     * Read the file and build a mass
     * @param line
     * @return A mass
     */
    private Mass massCommand (Scanner line) {
        int id = line.nextInt();
        double x = line.nextDouble();
        double y = line.nextDouble();
        double mass = line.nextDouble();
        return new Mass(id, x, y, mass);
    }

    /**
     * Read the file and build a mass
     * @param line
     * @param sim
     * @return A spring
     */
    private Spring springCommand (Scanner line, Simulation sim) {
        int m1 = line.nextInt();
        int m2 = line.nextInt();
        double restLength = line.nextDouble();
        double ks = line.nextDouble();

        if (ks > 0) {
            return new Spring(sim.getMass(m1), sim.getMass(m2), restLength, ks);
        }
        else {
            return new Bar(sim.getMass(m1), sim.getMass(m2), restLength, ks);
        }
    }

    /**
     * Read the file and build a muscle
     * @param line
     * @param sim
     * @return A muscle
     */
    private Muscle muscleCommand (Scanner line, Simulation sim) {
        int m1 = line.nextInt();
        int m2 = line.nextInt();
        double restLength = line.nextDouble();
        double ks = line.nextDouble();
        double amplitude = line.nextDouble();

        return new Muscle(
                sim.getMass(m1), sim.getMass(m2), restLength, ks, amplitude);

    }
    
    /*
     * Set for gravity force. Use default value for invalid inputs
     */
    private void setGravity(Scanner line) {
        double direction, magnitude;
        
        if (line.hasNextDouble()){
            direction = line.nextDouble();
            Global.setGravityDirection(direction);
            Global.setGravityDirectionDefault(direction);
        }
        else{
            direction = Global.getGravityDirectionDefault();
        }
        
        if (line.hasNextDouble()){
            magnitude = line.nextDouble();
            Global.setGravityMagnitude(magnitude);
            Global.setGravityMagnitudeDefault(magnitude);
        }
        else{
            magnitude = Global.getGravityMagnitudeDefault();
        }
        
        Global.setGravityDirection(direction);
        Global.setGravityMagnitude(magnitude);
    }
    
    /**
     * Set for viscosity force. Use default value for invalid inputs
     * @param line
     */
    private void setViscosity(Scanner line){
        double scaleValue;
        
        if (line.hasNextDouble()){
            scaleValue = line.nextDouble();
            Global.setViscosity(scaleValue);
            Global.setViscosityDefault(scaleValue);
        }
        else{
            scaleValue = Global.getViscosityDefault();
        }
        
        Global.setViscosity(scaleValue);
    }
    
    /**
     * Set for center mass force. Use default value for invalid inputs
     * @param line
     */
    private void setCenterMassForce(Scanner line) {
        double magnitude, exponent;
        
        if (line.hasNextDouble()){
            magnitude = line.nextDouble();
            Global.setCenterMassMagnitude(magnitude);
            Global.setCenterMassMagnitudeDefault(magnitude);
        }
        else{
            magnitude = Global.getCenterMassMagnitudeDefault();
        }
        
        if (line.hasNextDouble()){
            exponent = line.nextDouble();
            Global.setCenterMassExponent(exponent);
            Global.setCenterMassExponentDefault(exponent);
        }
        else{
            exponent = Global.getCenterMassExponentDefault();
        }

        Global.setCenterMassMagnitude(magnitude);
        Global.setCenterMassExponent(exponent);
    }
    
    /**
     * Set for wall repulsion force. Use default value for invalid inputs
     * @param line
     */
    private void setWallForce(Scanner line) {
        double magnitude, exponent;
        
        if (line.nextDouble() == 1){
            if (line.hasNextDouble()){
                magnitude = line.nextDouble();
                Global.setWallTopMagnitude(magnitude);
                Global.setWallTopMagnitudeDefault(magnitude);
            }
            else {
                magnitude = Global.getWallTopMagnitudeDefault();
            }
            
            if (line.hasNextDouble()){
                exponent = line.nextDouble();
                Global.setWallTopExponent(exponent);
                Global.setWallTopExponentDefault(exponent);
            }
            else {
                exponent = Global.getWallTopExponentDefault();
            }
        }
        else if (line.nextDouble() == 2){
            if (line.hasNextDouble()){
                magnitude = line.nextDouble();
                Global.setWallLeftMagnitude(magnitude);
                Global.setWallLeftMagnitudeDefault(magnitude);
            }
            else {
                magnitude = Global.getWallLeftMagnitudeDefault();
            }
            
            if (line.hasNextDouble()){
                exponent = line.nextDouble();
                Global.setWallLeftExponent(exponent);
                Global.setWallLeftExponentDefault(exponent);
            }
            else {
                exponent = Global.getWallLeftExponentDefault();
            }    
        }
        else if (line.nextDouble() == 3){
            if (line.hasNextDouble()){
                magnitude = line.nextDouble();
                Global.setWallLeftMagnitude(magnitude);
                Global.setWallLeftMagnitudeDefault(magnitude);
            }
            else {
                magnitude = Global.getWallLeftMagnitudeDefault();
            }
            
            if (line.hasNextDouble()){
                exponent = line.nextDouble();
                Global.setWallLeftExponent(exponent);
                Global.setWallLeftExponentDefault(exponent);
            }
            else {
                exponent = Global.getWallLeftExponentDefault();
            } 
        }
        else if (line.nextDouble() == 4){
            if (line.hasNextDouble()){
                magnitude = line.nextDouble();
                Global.setWallLeftMagnitude(magnitude);
                Global.setWallLeftMagnitudeDefault(magnitude);
            }
            else {
                magnitude = Global.getWallLeftMagnitudeDefault();
            }
            
            if (line.hasNextDouble()){
                exponent = line.nextDouble();
                Global.setWallLeftExponent(exponent);
                Global.setWallLeftExponentDefault(exponent);
            }
            else {
                exponent = Global.getWallLeftExponentDefault();
            } 
        }
    }
}
